package com.configtools.service;

import com.configtools.model.ExcelSheet;
import com.configtools.model.JavaClass;
import com.configtools.model.JavaField;
import lombok.extern.slf4j.Slf4j;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 代码生成服务
 * 负责使用FreeMarker模板生成Java代码
 * 
 * @author ConfigTools Team
 * @version 1.0.0
 */
@Slf4j
public class CodeGeneratorService {
    
    private final Configuration freemarkerConfig;
    
    public CodeGeneratorService() {
        this.freemarkerConfig = createFreemarkerConfig();
    }
    
    /**
     * 生成Java代码
     * 
     * @param excelSheets Excel工作表信息列表
     * @param outputDirectory 输出目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    public void generateJavaCode(List<ExcelSheet> excelSheets, String outputDirectory, 
                                String packageName, String author) throws Exception {
        log.info("开始生成Java代码，输出目录: {}", outputDirectory);
        
        if (excelSheets == null || excelSheets.isEmpty()) {
            throw new IllegalArgumentException("Excel工作表信息列表不能为空");
        }
        
        // 创建输出目录
        File outputDir = new File(outputDirectory);
        if (!outputDir.exists()) {
            if (!outputDir.mkdirs()) {
                throw new IOException("无法创建输出目录: " + outputDirectory);
            }
        }
        
        // 生成Bean类
        generateBeanClasses(excelSheets, outputDirectory, packageName, author);
        
        // 生成Container类
        generateContainerClasses(excelSheets, outputDirectory, packageName, author);
        
        // 生成Manager类
        generateManagerClass(excelSheets, outputDirectory, packageName, author);
        
        log.info("Java代码生成完成");
    }
    
    /**
     * 生成Bean类
     * 
     * @param excelSheets Excel工作表信息列表
     * @param outputDirectory 输出目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateBeanClasses(List<ExcelSheet> excelSheets, String outputDirectory, 
                                   String packageName, String author) throws Exception {
        log.info("开始生成Bean类...");
        
        String beanPackage = packageName + ".bean";
        String beanDirectory = outputDirectory + "/" + beanPackage.replace(".", "/");
        
        // 创建Bean目录
        File beanDir = new File(beanDirectory);
        if (!beanDir.exists() && !beanDir.mkdirs()) {
            throw new IOException("无法创建Bean目录: " + beanDirectory);
        }
        
        // 生成BaseCfgBean基类
        generateBaseCfgBean(beanDirectory, packageName, author);
        
        // 生成各个配置Bean类
        for (ExcelSheet sheet : excelSheets) {
            generateBeanClass(sheet, beanDirectory, beanPackage, author);
        }
        
        log.info("Bean类生成完成");
    }
    
    /**
     * 生成Container类
     * 
     * @param excelSheets Excel工作表信息列表
     * @param outputDirectory 输出目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateContainerClasses(List<ExcelSheet> excelSheets, String outputDirectory, 
                                       String packageName, String author) throws Exception {
        log.info("开始生成Container类...");
        
        String containerPackage = packageName + ".container";
        String containerDirectory = outputDirectory + "/" + containerPackage.replace(".", "/");
        
        // 创建Container目录
        File containerDir = new File(containerDirectory);
        if (!containerDir.exists() && !containerDir.mkdirs()) {
            throw new IOException("无法创建Container目录: " + containerDirectory);
        }
        
        // 生成BaseCfgContainer基类
        generateBaseCfgContainer(containerDirectory, packageName, author);
        
        // 生成各个配置Container类
        for (ExcelSheet sheet : excelSheets) {
            generateContainerClass(sheet, containerDirectory, containerPackage, packageName, author);
        }
        
        log.info("Container类生成完成");
    }
    
    /**
     * 生成Manager类
     * 
     * @param excelSheets Excel工作表信息列表
     * @param outputDirectory 输出目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateManagerClass(List<ExcelSheet> excelSheets, String outputDirectory, 
                                    String packageName, String author) throws Exception {
        log.info("开始生成Manager类...");
        
        String managerPackage = packageName;
        String managerDirectory = outputDirectory + "/" + managerPackage.replace(".", "/");
        
        // 创建Manager目录
        File managerDir = new File(managerDirectory);
        if (!managerDir.exists() && !managerDir.mkdirs()) {
            throw new IOException("无法创建Manager目录: " + managerDirectory);
        }
        
        // 生成GameDataManager类
        generateGameDataManager(excelSheets, managerDirectory, managerPackage, packageName, author);
        
        log.info("Manager类生成完成");
    }
    
    /**
     * 生成BaseCfgBean基类
     * 
     * @param beanDirectory Bean目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateBaseCfgBean(String beanDirectory, String packageName, String author) throws Exception {
        // 准备模板数据
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", packageName);
        dataModel.put("author", author);
        
        // 使用FTL模板生成BaseCfgBean
        String baseBeanContent = generateFromTemplate("base-bean.ftl", dataModel);
        String baseBeanFile = beanDirectory + "/BaseCfgBean.java";
        
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(baseBeanFile), StandardCharsets.UTF_8)) {
            writer.write(baseBeanContent);
        }
        
        log.info("生成BaseCfgBean: {}", baseBeanFile);
    }
    
    /**
     * 生成BaseCfgContainer基类
     * 
     * @param containerDirectory Container目录
     * @param packageName 包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateBaseCfgContainer(String containerDirectory, String packageName, String author) throws Exception {
        // 准备模板数据
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", packageName);
        dataModel.put("author", author);
        
        // 使用FTL模板生成BaseCfgContainer
        String baseContainerContent = generateFromTemplate("base-container.ftl", dataModel);
        String baseContainerFile = containerDirectory + "/BaseCfgContainer.java";
        
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(baseContainerFile), StandardCharsets.UTF_8)) {
            writer.write(baseContainerContent);
        }
        
        log.info("生成BaseCfgContainer: {}", baseContainerFile);
    }
    
    /**
     * 生成Bean类
     * 
     * @param sheet Excel工作表信息
     * @param beanDirectory Bean目录
     * @param beanPackage Bean包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateBeanClass(ExcelSheet sheet, String beanDirectory, String beanPackage, String author) throws Exception {
        JavaClass javaClass = sheet.getJavaClass();
        
        // 准备模板数据
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", beanPackage);
        dataModel.put("excelName", sheet.getExcelFileName());
        dataModel.put("sheetName", sheet.getSheetName());
        dataModel.put("beanClassName", javaClass.getClassName());
        dataModel.put("baseBeanClassName", "BaseCfgBean");
        dataModel.put("author", author);
        
        // 处理字段信息
        List<Map<String, String>> fields = new ArrayList<>();
        for (JavaField field : javaClass.getFields()) {
            Map<String, String> fieldInfo = new HashMap<>();
            fieldInfo.put("name", field.getName());
            fieldInfo.put("type", field.getType());
            fieldInfo.put("desc", field.getComment());
            fields.add(fieldInfo);
        }
        dataModel.put("fields", fields);
        
        // 生成Bean类代码
        String beanContent = generateFromTemplate("cfg-bean.ftl", dataModel);
        String beanFile = beanDirectory + "/" + javaClass.getClassName() + ".java";
        
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(beanFile), StandardCharsets.UTF_8)) {
            writer.write(beanContent);
        }
        
        log.info("生成Bean类: {}", beanFile);
    }
    
    /**
     * 生成Container类
     * 
     * @param sheet Excel工作表信息
     * @param containerDirectory Container目录
     * @param containerPackage Container包名
     * @param packageName 基础包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateContainerClass(ExcelSheet sheet, String containerDirectory, String containerPackage, 
                                     String packageName, String author) throws Exception {
        JavaClass javaClass = sheet.getJavaClass();
        
        // 准备模板数据
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", containerPackage);
        dataModel.put("beanFullName", packageName + ".bean." + javaClass.getClassName());
        dataModel.put("beanClassName", javaClass.getClassName());
        dataModel.put("containerClassName", javaClass.getClassName() + "Container");
        dataModel.put("excelName", sheet.getExcelFileName());
        dataModel.put("sheetName", sheet.getSheetName());
        dataModel.put("author", author);
        
        // 生成Container类代码
        String containerContent = generateFromTemplate("container.ftl", dataModel);
        String containerFile = containerDirectory + "/" + javaClass.getClassName() + "Container.java";
        
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(containerFile), StandardCharsets.UTF_8)) {
            writer.write(containerContent);
        }
        
        log.info("生成Container类: {}", containerFile);
    }
    
    /**
     * 生成GameDataManager类
     * 
     * @param excelSheets Excel工作表信息列表
     * @param managerDirectory Manager目录
     * @param managerPackage Manager包名
     * @param packageName 基础包名
     * @param author 作者
     * @throws Exception 生成异常
     */
    private void generateGameDataManager(List<ExcelSheet> excelSheets, String managerDirectory, String managerPackage, 
                                       String packageName, String author) throws Exception {
        // 准备模板数据
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", managerPackage);
        dataModel.put("baseBeanPackage", packageName + ".bean");
        dataModel.put("baseContainerPackage", packageName + ".container");
        dataModel.put("beanPackage", packageName + ".bean");
        dataModel.put("containerPackage", packageName + ".container");
        dataModel.put("managerClassName", "GameDataManager");
        dataModel.put("author", author);
        
        // 处理Bean类列表
        List<String> beanClasses = excelSheets.stream()
                .map(sheet -> sheet.getJavaClass().getClassName())
                .collect(Collectors.toList());
        dataModel.put("beanClasses", beanClasses);
        
        // 生成Manager类代码
        String managerContent = generateFromTemplate("manager.ftl", dataModel);
        String managerFile = managerDirectory + "/GameDataManager.java";
        
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(managerFile), StandardCharsets.UTF_8)) {
            writer.write(managerContent);
        }
        
        log.info("生成GameDataManager: {}", managerFile);
    }
    
    /**
     * 从模板生成代码
     * 
     * @param templateName 模板名称
     * @param dataModel 数据模型
     * @return 生成的代码
     * @throws Exception 生成异常
     */
    private String generateFromTemplate(String templateName, Map<String, Object> dataModel) throws Exception {
        try {
            Template template = freemarkerConfig.getTemplate(templateName);
            StringWriter writer = new StringWriter();
            template.process(dataModel, writer);
            return writer.toString();
        } catch (TemplateException | IOException e) {
            throw new Exception("模板处理失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建FreeMarker配置
     * 
     * @return FreeMarker配置
     */
    private Configuration createFreemarkerConfig() {
        Configuration config = new Configuration(Configuration.VERSION_2_3_32);
        
        try {
            // 设置模板目录为项目根目录下的config/templates
            File templateDir = new File("config/templates");
            if (!templateDir.exists()) {
                // 如果不存在，尝试从类路径加载
                config.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "templates");
            } else {
                config.setDirectoryForTemplateLoading(templateDir);
            }
        } catch (IOException e) {
            // 出错时使用类路径加载
            config.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "templates");
            log.warn("无法设置模板目录，使用类路径加载: {}", e.getMessage());
        }
        
        // 设置默认编码
        config.setDefaultEncoding("UTF-8");
        
        // 设置数字格式
        config.setNumberFormat("0.######");
        
        return config;
    }
}
